﻿#pragma once

#include <cstdint>
#include <ctime>
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace kratos {
namespace redis {

/**
 * Redis命令错误码.
 */
enum class RedisError : std::int32_t {
  SUCCESS = 1, ///< 成功
  FAILURE,     ///< 失败
  TIMEOUT,     ///< 超时
};

/**
 * Redis命令执行返回结果.
 */
class Result {
public:
  virtual ~Result() {}
  /**
   * 获取执行的命令.
   *
   * \return
   */
  virtual auto get_command() const -> const std::string & = 0;
  /**
   * 获取RedisReply*.
   *
   * \return
   */
  virtual auto get_reply() const -> void * = 0;
  /**
   * 从结果内获取字符串.
   *
   * \param [OUT] s 返回值
   * \return true或false
   */
  virtual auto get_return(std::string &s) const -> bool = 0;
  /**
   * 从结果内获取字符串数组.
   *
   * \param [OUT] v 返回值
   * \return true或false
   */
  virtual auto get_return(std::vector<std::string> &v) const -> bool = 0;
  /**
   * 从结果内获取字符串列表.
   *
   * \param [OUT] v 返回值
   * \return true或false
   */
  virtual auto get_return(std::list<std::string> &v) const -> bool = 0;
  /**
   * 从结果内获取字符串哈希表.
   *
   * \param [OUT] m 返回值
   * \return true或false
   */
  virtual auto get_return(std::unordered_map<std::string, std::string> &m)
      const -> bool = 0;
  /**
   * 从结果内获取字符串集合.
   *
   * \param [OUT] s 返回值
   * \return true或false
   */
  virtual auto get_return(std::unordered_set<std::string> &s) const -> bool = 0;
  /**
   * 从结果内获取数量值
   *
   * \param [OUT] size 返回值
   * \return true或false
   */
  virtual auto get_return(std::size_t &size) const -> bool = 0;
  /**
   * 从结果内获取布尔值.
   *
   * \param [OUT] b 返回值
   * \return true或false
   */
  virtual auto get_return(bool &b) const -> bool = 0;
  /**
   * 是否成功.
   *
   * \return
   */
  virtual auto is_success() const -> bool = 0;
  /**
   * 获取错误描述.
   *
   * \return
   */
  virtual auto get_error() const -> const std::string & = 0;
  /**
   * 获取错误码.
   *
   * \return
   */
  virtual auto get_error_code() const -> RedisError = 0;
};

/**
 * Redis异步回调.
 */
using RedisHandler = std::function<void(const Result &, std::uint64_t)>;

/**
 * Redis组件接口.
 */
class Redis {
public:
  virtual ~Redis() {}
  /**
   * 启动.
   *
   * \return true或false
   */
  virtual auto start() -> bool = 0;
  /**
   * 关闭.
   *
   * \return true或false
   */
  virtual auto stop() -> bool = 0;
  /**
   * 主循环.
   *
   * \param ms 当前时间戳，毫秒
   * \return 本次调用完成的Redis操作数量
   */
  virtual auto update(std::time_t ms) -> std::size_t = 0;
  /**
   * 添加Redis主机.
   *
   * \param name 主机名
   * \param host 主机地址
   * \param port 端口
   * \param user 用户名
   * \param passwd 密码
   * \return true或false
   */
  virtual auto add_host(const std::string &name, const std::string &host,
                        int port, const std::string &user,
                        const std::string &passwd) -> bool = 0;
  /**
   * 执行异步Redis命令.
   *
   * \param name 主机名
   * \param command 命令
   * \param timeout 超时，毫秒
   * \param handler 回调函数
   * \param user_data 用户数据
   * \return true或false
   */
  virtual auto do_command(const std::string &name, const std::string &command,
                          std::time_t timeout, RedisHandler handler, std::uint64_t user_data)
      -> bool = 0;
  /**
   * 在协程内执行同步Redis命令.
   *
   * \param name 主机名
   * \param command 命令
   * \param timeout 超时，毫秒
   * \return 执行结果
   */
  virtual auto do_command_co(const std::string &name,
                             const std::string &command, std::time_t timeout)
      -> std::unique_ptr<Result> = 0;
};

} // namespace redis
} // namespace kratos
